import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.TextArea;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JTextField;

public class TrelisDijagram extends JFrame {

    int visina_frejma;
    int sirina_frejma;
    static String ulaz = "11001110000000000000";
    int index = 0;
    static private ArrayList<Putanja> putanje;
    private Tacka[][] matrica;
    static private int n;
    static public Koder g;
    private TrelisDijagram.MemorijaDekodera window;

    public TrelisDijagram() {
	super("Trelis dijagram");
	n = Koder.broj_celija - 1;
	sirina_frejma = 200 + 40 * (ulaz.length() / 2);
	visina_frejma = (int) (100 + 40 * Math.pow(2, n));
	this.setSize(sirina_frejma, visina_frejma);
	this.setResizable(false);
	this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
	this.addKeyListener((KeyListener) new TrelisDijagram.keyListener());
	this.addWindowListener((WindowListener) new TrelisDijagram.windowListener());
	putanje = new ArrayList<Putanja>();
	window = new TrelisDijagram.MemorijaDekodera();
	this.setVisible(true);

    }

    private class windowListener extends WindowAdapter {
	public void windowClosed(WindowEvent event) {
	    g.setEnabled(true);
	}
    }

    private class keyListener extends KeyAdapter {

	public void keyPressed(KeyEvent event) {
	    if (event.isControlDown()) {
		if (event.getKeyCode() == KeyEvent.VK_LEFT) {
		    if (index > 0) {
			TrelisDijagram.this.index -= 2;
			TrelisDijagram.this.repaint();
		    }

		}
		if (event.getKeyCode() == KeyEvent.VK_RIGHT) {
		    if (index < ulaz.length() - 1) {
			TrelisDijagram.this.index += 2;
			TrelisDijagram.this.repaint();
		    }
		}
		if (event.getKeyCode() == KeyEvent.VK_ENTER) {
		    if (event.isAltDown()) {
			window.setVisible(true);
		    } else {
			new VectorInput();
		    }

		}
	    }
	}
    }

    private class VectorInput extends JDialog {
	public JTextField inputField;

	public VectorInput() {
	    super(TrelisDijagram.this, "Ulaz");
	    inputField = new JTextField();
	    inputField.addKeyListener((KeyListener) new TrelisDijagram.VectorInput.keyListener());
	    inputField.setText(TrelisDijagram.ulaz);
	    this.add(inputField);
	    ;
	    this.setSize(300, 50);
	    this.setResizable(false);
	    this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
	    this.setLocation(TrelisDijagram.this.getLocation().x + sirina_frejma / 2 - this.getWidth() - 50,
		    TrelisDijagram.this.getLocation().y + visina_frejma / 2 - 200 - 40);
	    this.setVisible(true);
	}

	private class keyListener extends KeyAdapter {

	    public void keyPressed(KeyEvent event) {
		char c = event.getKeyChar();

		if (((c == KeyEvent.VK_0) || (c == KeyEvent.VK_1))) {
		    if (inputField.isEditable() == false) {
			inputField.setEditable(true);
		    }
		} else if (c == KeyEvent.VK_BACK_SPACE) {
		    if (inputField.isEditable() == false) {
			inputField.setEditable(true);
		    }
		} else if (c == KeyEvent.VK_ENTER) {

		    TrelisDijagram.ulaz = inputField.getText();

		    dispose();
		    TrelisDijagram.this.repaint();

		} else if (c == KeyEvent.VK_ESCAPE) {
		    dispose();
		} else {
		    if (inputField.isEditable() == true) {
			inputField.setEditable(false);
			inputField.setBackground(Color.white);
			inputField.requestFocusInWindow();
		    }
		}
	    }
	}
    }

    private class MemorijaDekodera extends JDialog {

	TextArea text;

	public MemorijaDekodera() {
	    super(TrelisDijagram.this, "Memorija dekodera");
	    setSize(600, 400);
	    text = new java.awt.TextArea();
	    this.popuni();
	    text.setEditable(false);
	    text.setBackground(Color.white);
	    this.add(text);
	    this.setVisible(false);
	    this.setDefaultCloseOperation(HIDE_ON_CLOSE);
	}

	public void popuni() {
	    Font font = new Font("Courier", Font.BOLD, 20);
	    text.setFont(font);
	    text.setText("");
	    for (int i = 0; i < TrelisDijagram.putanje.size(); i++) {
		Putanja a = TrelisDijagram.putanje.get(i);
		text.append(a.traka + " " + a.sekvenca + " " + a.izlaz + " " + a.metrika + "\n");
	    }
	}
    }

    private class Tacka {
	Graphics2D g2 = (Graphics2D) TrelisDijagram.this.getGraphics();
	private Ellipse2D.Double e;
	public Point2D.Double centar;
	public int radius = 4;

	public Tacka(int x, int y) {
	    e = new Ellipse2D.Double(x - radius / 2, y - radius / 2, radius, radius);
	    g2.setPaint(Color.black);
	    g2.setStroke(new BasicStroke(1));
	    g2.setRenderingHints(new RenderingHints(RenderingHints.KEY_FRACTIONALMETRICS,
		    RenderingHints.VALUE_FRACTIONALMETRICS_ON));
	    g2.draw(e);
	    g2.setPaint(Color.black);
	    g2.fill(e);
	    centar = new Point2D.Double(x, y);
	}
    }

    private Tacka[] crtajKolonu(int x) {
	Tacka[] result = new Tacka[(int) Math.pow(2, n)];
	for (int i = 0; i < Math.pow(2, n); i++) {
	    result[i] = new Tacka(x, 80 + 40 * i);
	}
	return result;
    }

    private Tacka[][] crtajMatricu(int m) {
	Tacka[][] matrica = new Tacka[m][];
	for (int i = 0; i < m; i++) {
	    Tacka[] kolona = this.crtajKolonu(100 + 40 * i);
	    matrica[i] = kolona;
	}
	return matrica;
    }

    private void crtajPutanje(ArrayList<Putanja> putanje) {
	Graphics2D g2 = (Graphics2D) TrelisDijagram.this.getGraphics();
	for (int i = 0; i < putanje.size(); i++) {
	    for (int j = 0; j < putanje.get(i).traka.size() - 1; j++) {
		int index1 = putanje.get(i).traka.get(j);
		int index2 = putanje.get(i).traka.get(j + 1);
		Point2D.Double tacka1 = this.matrica[j][index1].centar;
		Point2D.Double tacka2 = this.matrica[j + 1][index2].centar;
		Line2D.Double linija = new Line2D.Double(tacka1, tacka2);
		g2.setStroke(new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
		if (index2 == Integer.parseInt(Koder.tranzicija[index1][0], 2)) {
		    g2.setPaint(Color.yellow);
		} else {
		    g2.setPaint(Color.red);
		}
		g2.draw(linija);
	    }
	}
    }

    private void pisiLabele() {
	Graphics2D g2 = (Graphics2D) TrelisDijagram.this.getGraphics();
	Font font = new Font("Courier", Font.TYPE1_FONT, 20);
	g2.setFont(font);
	g2.setColor(Color.black);
	for (int i = 0; i < Math.pow(2, n); i++) {
	    g2.drawString(DijagramStanja.toBin(i, n), 20, 88 + 40 * i);
	}
	for (int i = 0; i < index; i = i + 2) {
	    g2.drawString(ulaz.substring(i, i + 2), 107 + 40 * i / 2, 50);
	}
    }

    public void paint(Graphics g) {
	Graphics2D g2 = (Graphics2D) g;
	sirina_frejma = 200 + 40 * (ulaz.length() / 2);
	visina_frejma = (int) (100 + 40 * Math.pow(2, n));
	this.setSize(sirina_frejma, visina_frejma);
	if (isOpaque()) { // paint background
	    GradientPaint gp = new GradientPaint(0, visina_frejma, Color.blue, sirina_frejma, 0, Color.white);
	    g2.setPaint(gp);
	    g.fillRect(0, 0, sirina_frejma, visina_frejma);
	}

	putanje = Putanja.viterbi(ulaz.substring(0, index));
	matrica = crtajMatricu(ulaz.length() / 2 + 1);
	pisiLabele();
	crtajPutanje(putanje);
	window.popuni();
    }
}
